home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / tex / rail.zip / RAIL.C < prev    next >
C/C++ Source or Header  |  1992-01-15  |  10KB  |  695 lines

  1. /*
  2.  * rail.c - railroad diagram utility
  3.  *
  4.  * 09-Jul-1990 L. Rooijakkers
  5.  * 09-Oct-1990 L. Rooijakkers
  6.  * 07-Feb-1991 L. Rooijakkers    indexing, embedded options
  7.  * 08-Feb-1991 L. Rooijakkers    small mods for version 1.0 #0
  8.  * 12-Feb-1991 L. Rooijakkers    minor portability fixes
  9.  *
  10.  */
  11.  
  12. #ifndef lint
  13. static char SccsId[]="@(#)rail 12-Feb-1991";
  14. #endif
  15.  
  16. #define USAGE    "usage: %s [-+acdit] [file]\n"
  17.  
  18. #include <stdio.h>
  19.  
  20. #include "patchlev.h"
  21. #include "rail.h"
  22. #include "gram.h"
  23.  
  24. extern char *strcat(), *strcpy();
  25.  
  26. char *myname;        /* program name */
  27.  
  28. char *file;        /* input file */
  29. int my_line;        /* input line */
  30. extern FILE *yyin;    /* lex input stream */
  31.  
  32. char *outfile;        /* output file */
  33. FILE *outf;        /* output stream */
  34.  
  35. int newline;        /* stdout requires a newline */
  36.  
  37. IDTYPE *idlist;        /* identifier list */
  38.  
  39. IDTYPE *errorid;    /* identifier for errors */
  40.  
  41. /* options */
  42.  
  43. int altstar;        /* alternate star */
  44. int chkgram;        /* check grammar */
  45. int treelist;        /* list rule trees */
  46. int genindex;        /* generate index entry for left hand sides */
  47.  
  48. #ifdef YYDEBUG
  49. extern int yydebug;    /* show yacc debugging */
  50. #endif
  51.  
  52. int anonymous;        /* anonymous rules */
  53.  
  54. main(argc,argv)
  55. int argc;
  56. char **argv;
  57. {
  58.     char *arg, **argp;
  59.     unsigned len;
  60.  
  61.     printf("This is Rail, Version %s #%d\n",VERSION,PATCHLEVEL);
  62.     newline=0;
  63.  
  64.     myname=argv[0];
  65.  
  66.     for(argp = &argv[1];(arg = *argp)!=NULL;argp++) {
  67.         if(*arg!='-' && *arg!='+')
  68.             break;
  69.         if(setopt(*arg,arg+1)==0)
  70.             usage();
  71.     }
  72.  
  73.     if(arg!=NULL && *++argp!=NULL)
  74.         usage();
  75.  
  76.     if(arg==NULL) {
  77.         file="stdin";
  78.         outfile="stdout";
  79.         yyin=stdin;
  80.         outf=stdout;
  81.     } else {
  82.         len=strlen(arg)+5;
  83.         file=mcheck(malloc(len));
  84.         outfile=mcheck(malloc(len));
  85.         strcat(strcpy(file,arg),".rai");
  86.         strcat(strcpy(outfile,arg),".rao");
  87.         if((yyin=fopen(file,"r"))==NULL) {
  88.             perror(file);
  89.             exit(1);
  90.         }
  91.         if((outf=fopen(outfile,"w"))==NULL) {
  92.             perror(outfile);
  93.             exit(1);
  94.         }
  95.     }
  96.  
  97.     printf("(%s",file);
  98.     newline=1;
  99.  
  100.     my_line=1;
  101.  
  102.     fprintf(outf,"%% This file was generated by '%s' from '%s'\n",myname,file);
  103.  
  104.     if(yyparse()!=0)
  105.         exit(1);
  106.  
  107.     printf(")\n");
  108.     newline=0;
  109.  
  110.     file=NULL;
  111.  
  112.     if(chkgram) {
  113.         checkdefs();
  114.         if(anonymous)
  115.             error("unnamed rules are present",(char *)NULL);
  116.     }
  117.  
  118.     exit(0);
  119.     /*NOTREACHED*/
  120. }
  121.  
  122. int setopt(c,s)
  123. char c, *s;
  124. {
  125.     int set;
  126.  
  127.     set = c=='-';
  128.  
  129.     while(*s!='\0') {
  130.  
  131.         switch(*s++) {
  132.  
  133.         case 'a':
  134.             altstar=set;
  135.             break;
  136.  
  137.         case 'c':
  138.             chkgram=set;
  139.             break;
  140.  
  141.         case 'd':
  142. #ifdef YYDEBUG
  143.             yydebug=set;
  144. #endif
  145.             break;
  146.  
  147.         case 'i':
  148.             genindex=set;
  149.             break;
  150.  
  151.         case 't':
  152.             treelist=set;
  153.             break;
  154.  
  155.         default:
  156.             return 0;
  157.         }
  158.     }
  159.  
  160.     return 1;
  161. }
  162.  
  163. usage()
  164. {
  165.     fprintf(stderr,USAGE,myname);
  166.     exit(1);
  167. }
  168.  
  169. /* error routine for yyparse() */
  170.  
  171. yyerror(s)
  172. char *s;
  173. {
  174.     fatal("%s",s);
  175. }
  176.  
  177. /* wrap-up routine for yylex() */
  178.  
  179. yywrap()
  180. {
  181.     return(1);
  182. }
  183.  
  184. /* check for non-NULL pointer */
  185.  
  186. char *mcheck(s)
  187. char *s;
  188. {
  189.     if(s==NULL)
  190.         fatal("out of memory",(char *)NULL);
  191.  
  192.     return(s);
  193. }
  194.  
  195. /* make a new body */
  196.  
  197. BODYTYPE *newbody(kind,body1,body2)
  198. int kind;
  199. BODYTYPE *body1, *body2;
  200. {
  201.     BODYTYPE *body;
  202.  
  203.     body=(BODYTYPE *)mcheck(malloc(sizeof(BODYTYPE)));
  204.     body->kind=kind;
  205.     body->nlist=0;
  206.     body->done=0;
  207.     body->id=NULL;
  208.     body->text=NULL;
  209.     body->annot=NULL;
  210.  
  211.     if(body1!=NULL)
  212.         body->list[body->nlist++]=body1;
  213.  
  214.     if(body2!=NULL)
  215.         body->list[body->nlist++]=body2;
  216.  
  217.     return(body);
  218. }
  219.  
  220. /* free a body recursively */
  221.  
  222. freebody(body)
  223. BODYTYPE *body;
  224. {
  225.     int i;
  226.  
  227.     if(body==NULL)
  228.         return;
  229.  
  230.     for(i=0;i<body->nlist;i++)
  231.         freebody(body->list[i]);
  232.  
  233.     if(body->text!=NULL) {
  234.         /* should free text here */
  235.     }
  236.  
  237.     free((char *)body);
  238. }
  239.  
  240. /* test if a body is empty */
  241.  
  242. int isemptybody(body)
  243. BODYTYPE *body;
  244. {
  245.     return(body==NULL || body->kind==EMPTY);
  246. }
  247.  
  248. /* add to a body list */
  249.  
  250. static addlist(body1,body2)
  251. BODYTYPE *body1, *body2;
  252. {
  253.     if(body1->nlist>=MAXLIST) {
  254.         yyerror("list too long");
  255.     } else
  256.         body1->list[body1->nlist++]=body2;
  257. }
  258.  
  259. /* add two body lists (for CAT, BAR, PLUS) */
  260.  
  261. BODYTYPE *addbody(kind,body1,body2)
  262. int kind;
  263. BODYTYPE *body1, *body2;
  264. {
  265.     BODYTYPE *body;
  266.     int i;
  267.  
  268.     if(body1->kind==kind && !(kind==BAR && body1->done) ) {
  269.         body=body1;
  270.     } else {
  271.         body=newbody(kind,NULLBODY,NULLBODY);
  272.         addlist(body,body1);
  273.     }
  274.  
  275.     if(body2->kind==kind && !(kind==BAR && body2->done) ) {
  276.         for(i=0;i<body2->nlist;i++)
  277.             addlist(body,body2->list[i]);
  278.         free((char *)body2);
  279.     } else {
  280.         addlist(body,body2);
  281.     }
  282.  
  283.     return(body);
  284. }
  285.  
  286. /* reverse all concatenations (for PLUS) */
  287.  
  288. BODYTYPE *revbody(body)
  289. BODYTYPE *body;
  290. {
  291.     int i,j;
  292.     BODYTYPE *tmp;
  293.  
  294.     if(body->kind==CAT) {
  295.         for(i=0,j=body->nlist-1;i<j;i++,j--) {
  296.             tmp=body->list[i];
  297.             body->list[i]=body->list[j];
  298.             body->list[j]=tmp;
  299.         }
  300.     }
  301.  
  302.     for(i=0;i<body->nlist;i++)
  303.         body->list[i]=revbody(body->list[i]);
  304.  
  305.     return(body);
  306. }
  307.  
  308. /* print a body for debugging */
  309.  
  310. prtbody(indent,body)
  311. int indent;
  312. BODYTYPE *body;
  313. {
  314.     int i;
  315.  
  316.     fprintf(outf,"%% ");
  317.  
  318.     for(i=0;i<indent;i++)
  319.         fprintf(outf,". ");
  320.  
  321.     if(body==NULL)
  322.         fprintf(outf,"NULL\n");
  323.     else {
  324.         switch(body->kind) {
  325.  
  326.         case EMPTY:
  327.             fprintf(outf,"EMPTY");
  328.             break;
  329.  
  330.         case CAT:
  331.             fprintf(outf,"CAT");
  332.             break;
  333.  
  334.         case BAR:
  335.             fprintf(outf,"BAR");
  336.             break;
  337.  
  338.         case PLUS:
  339.             fprintf(outf,"PLUS");
  340.             break;
  341.  
  342.         case ANNOTE:
  343.             fprintf(outf,"ANNOTE [%s]",body->text);
  344.             break;
  345.  
  346.         case IDENT:
  347.             fprintf(outf,"IDENT %s",body->id->name);
  348.             break;
  349.  
  350.         case CR:
  351.             fprintf(outf,"CR");
  352.             break;
  353.  
  354.         case STRNG:
  355.             fprintf(outf,"STRNG '%s'",body->text);
  356.             break;
  357.  
  358.         default:
  359.             fprintf(outf,"UNKNOWN");
  360.             break;
  361.         }
  362.  
  363.         fprintf(outf," y=%d nexty=%d\n",body->ystart,body->ynext);
  364.  
  365.         for(i=0;i<body->nlist;i++)
  366.             prtbody(indent+1,body->list[i]);
  367.     }
  368. }
  369.  
  370. /* output a body */
  371.  
  372. outbody(id,body)
  373. IDTYPE *id;
  374. BODYTYPE *body;
  375. {
  376.     posbody(body,0);
  377.  
  378.     if(treelist)
  379.         prtbody(0,body);
  380.  
  381.     fprintf(outf,"\\rail@begin{%d}{",body->ynext);
  382.     if(id!=NULL) {
  383.         fprintf(outf,"%s",id->name);
  384.     }
  385.     fprintf(outf,"}\n");
  386.  
  387.     fmtbody(body,"");
  388.  
  389.     fprintf(outf,"\\rail@end\n");
  390. }
  391.  
  392. /* format a body */
  393.  
  394. fmtbody(body,cent)
  395. BODYTYPE *body;
  396. char *cent;
  397. {
  398.     BODYTYPE *body1;
  399.     int i;
  400.     char *next;
  401.  
  402.     switch(body->kind) {
  403.  
  404.     case EMPTY:
  405.         break;
  406.  
  407.     case CAT:
  408.         for(i=0;i<body->nlist;i++)
  409.             fmtbody(body->list[i],"");
  410.         break;
  411.  
  412.     case BAR:
  413.         next="\\rail@bar\n";
  414.         for(i=0;i<body->nlist;i++) {
  415.             body1=body->list[i];
  416.             fprintf(outf,next,body1->ystart);
  417.             next="\\rail@nextbar{%d}\n";
  418.             fmtbody(body1,"");
  419.         }
  420.         fprintf(outf,"\\rail@endbar\n");
  421.         break;
  422.  
  423.     case PLUS:
  424.         fprintf(outf,"\\rail@plus\n");
  425.         fmtbody(body->list[0],"");
  426.         body1=body->list[1];
  427.         fprintf(outf,"\\rail@nextplus{%d}\n",body1->ystart);
  428.         fmtbody(body1,"c");
  429.         fprintf(outf,"\\rail@endplus\n");
  430.         break;
  431.  
  432.     case ANNOTE:
  433.         fprintf(outf,"\\rail@annote[%s]\n",body->text);
  434.         break;
  435.  
  436.     case IDENT:
  437.         if(body->id->kind==TERM)
  438.             fprintf(outf,"\\rail@%stoken{%s",cent,body->id->name);
  439.         else
  440.             fprintf(outf,"\\rail@%snont{%s",cent,body->id->name);
  441.         if(body->annot!=NULL)
  442.             fprintf(outf,"\\rail@annotebox[%s]",body->annot);
  443.         fprintf(outf,"}\n");
  444.         break;
  445.  
  446.     case CR:
  447.         fprintf(outf,"\\rail@cr{%d}\n",body->ynext-1);
  448.         break;
  449.  
  450.     case STRNG:
  451.         fprintf(outf,"\\rail@%sterm{%s",cent,body->text);
  452.         if(body->annot!=NULL)
  453.             fprintf(outf,"\\rail@annotebox[%s]",body->annot);
  454.         fprintf(outf,"}\n");
  455.         break;
  456.  
  457.     default:
  458.         fprintf(outf,"\\rail@unknown\n");
  459.         break;
  460.     }
  461. }
  462.  
  463. /* position body (fill in height and ystart) */
  464.  
  465. posbody(body,ystart)
  466. BODYTYPE *body;
  467. {
  468.     BODYTYPE *body1;
  469.     int i;
  470.  
  471.     switch(body->kind) {
  472.  
  473.     case CAT:
  474.         body->ystart=ystart;
  475.         body->ynext=ystart+1;
  476.  
  477.         for(i=0;i<body->nlist;i++) {
  478.             body1=body->list[i];
  479.             if(body1->kind==CR) {
  480.                 body1->ystart=ystart;
  481.                 body1->ynext=body->ynext+2;
  482.                 ystart=body1->ynext-1;
  483.             } else
  484.                 posbody(body1,ystart);
  485.             if(body1->ynext>body->ynext)
  486.                 body->ynext=body1->ynext;
  487.         }
  488.         break;
  489.  
  490.     case BAR:
  491.     case PLUS:
  492.         body->ystart=ystart;
  493.         body->ynext=ystart+1;
  494.  
  495.         for(i=0;i<body->nlist;i++) {
  496.             body1=body->list[i];
  497.             posbody(body1,ystart);
  498.             ystart=body1->ynext;
  499.             if(body1->ynext>body->ynext)
  500.                 body->ynext=body1->ynext;
  501.         }
  502.         break;
  503.  
  504.     case CR:
  505.         body->ystart=ystart;
  506.         body->ynext=ystart+3;
  507.         break;
  508.  
  509.     case EMPTY:
  510.     case ANNOTE:
  511.     case IDENT:
  512.     case STRNG:
  513.     default:
  514.         body->ystart=ystart;
  515.         body->ynext=ystart+1;
  516.         break;
  517.     }
  518. }
  519.  
  520. /* output an index entry */
  521.  
  522. outindex(id)
  523. IDTYPE *id;
  524. {
  525.     if(id!=NULL)
  526.         fprintf(outf,"\\rail@index{%s}\n",id